import React, { Component, ComponentClass } from 'react';
import Taro from '@tarojs/taro';
import {connect} from 'react-redux'
import {View, Text, Block, ScrollView} from '@tarojs/components'
import {DateType} from '../../reducers/select-date'
import {selectDate} from '../../actions/select-date'
import {user} from "../../utils/user.service";
import {GET_ANNUAL_LEAVE_DAY_INFO, CHECK_DAY_INFO} from "../../constants/api";
import {http} from '../../utils/http';
import '../components/calendar/calendar-news.scss'

interface ServerDateData {
  date: string
  price: number
  seller_price?: number
  stock_balance?: number
  supplier_price?: number
}

interface Today {
  text: string
  todayText: string
  timestamp: number
  selftimestamp: number
  year: string
  month: string
  day: string
  count: number
  week: number
}

interface CurMonth {
  day: string
  year: string
  month: string
  count: number
  week: number
}

interface PrevMonth {
  count: number
  month: string
  year: string
}

interface NextMonth {
  month: string
  year: string
}

interface CalendarData {
  value: string  // 值
  valid: boolean // 是否有效
  isWeekend: boolean // 是否周末
  day: string // 日期
  prev: boolean // 是否上一月
  next: boolean // 是否下一月
  data?: ServerDateData // 服务器数据
}

interface StateType {
  curMonth: CurMonth
  prevMonth: PrevMonth
  nextMonth: NextMonth
  calendar: CalendarData[]
  start: string
  end: string
  goodId: string
  goodsId: string
  duration: CalendarData[]
  single: string
  confirmBtn: boolean
  range: string[]
  isGroup: boolean
}


type PageStateProps = {
  selectDate: DateType
}

type PageDispatchProps = {
  selectDateAction: (param: any) => void
}

type PageOwnProps = {
  type?: 'single' | 'range'
  data?: ServerDateData[]
  onConfirm?: (param: any) => void
  mode?: 'redux' | 'callback'
  category?: number
  onClose?: (param: any) => void
  day_end?: number
  time_end?: string
  lateNum?: number
  isGroup?: boolean
  env: any
}

type PageState = {}

type IProps = PageStateProps & PageDispatchProps & PageOwnProps

interface Calendar {
  props: IProps
}

@connect(({selectDate}) => ({
  selectDate,
}), (dispatch) => ({
  selectDateAction(data) {
    dispatch(selectDate(data))
  }
}))

class Calendar extends Component {
  state: StateType = {
    curMonth: {year: '', month: '', count: 0, week: 0},
    prevMonth: {month: '', year: '', count: 0},
    nextMonth: {month: '', year: ''},
    calendar: [],
    start: '',
    end: '',
    goodId: '',
    goodsId: '',
    duration: [],
    single: '',
    confirmBtn: false,
    range: [],
    isSeller: false,
    isGroup: true
  }
  static defaultProps = {
    type: 'single',
    data: [],
    lateNum: 0,
    goodsType: 1,
    continuousType: 1,
    onConfirm: () => {
    },
    selectDateAction: () => {
    },
    selectDate: {},
    mode: 'redux',
    onClose: () => {
    }
  }
  week = ['日', '一', '二', '三', '四', '五', '六']
  today: Today = {
    text: '',
    todayText: '',
    timestamp: 0,
    selftimestamp: 0,
    year: '',
    month: '',
    day: '',
    count: 0,
    week: 0
  }

  async getCalendarData() {
    const data = await http.HGet(GET_ANNUAL_LEAVE_DAY_INFO, {})
    Taro.setStorageSync('calendarData', data.data)
    return data.data
  }

  async componentDidMount() {
    const isGroup = this.props.isGroup ? this.props.isGroup : false
    const day_end = this.props.day_end ? this.props.day_end : 0
    const time_end = this.props.time_end ? this.props.time_end.split('.')[0] : '23:59:00'
    const tiqian = new Date(new Date().toLocaleDateString()).getTime() + day_end * 24 * 60 * 60 * 1000
    const todayTime = new Date()
    const minData = this.props.data.length > 0 ? new Date(this.props.data[0].date) : new Date()
    const now = (this.props.type === 'range' && this.props.time_end) ? new Date(tiqian) : minData
    const toDay = todayTime.getDate() < 10 ? '0' + todayTime.getDate() : `${todayTime.getDate()}`
    const toMonth = todayTime.getMonth() + 1 < 10 ? '0' + (todayTime.getMonth() + 1) : `${todayTime.getMonth() + 1}`
    const toYear = todayTime.getFullYear() < 10 ? '0' + todayTime.getFullYear() : `${todayTime.getFullYear()}`
    this.today.day = now.getDate() < 10 ? '0' + now.getDate() : `${now.getDate()}`
    this.today.month = now.getMonth() + 1 < 10 ? '0' + (now.getMonth() + 1) : `${now.getMonth() + 1}`
    this.today.year = now.getFullYear() < 10 ? '0' + now.getFullYear() : `${now.getFullYear()}`
    this.today.text = `${this.today.year}-${this.today.month}-${this.today.day}`
    this.today.todayText = `${toYear}-${toMonth}-${toDay}`
    this.today.timestamp = new Date(this.today.text).getTime()
    const selfText = `${toYear}-${toMonth}-${toDay} ${time_end}`
    this.today.selftimestamp = new Date(selfText).getTime()
    this.today.count = new Date(parseInt(this.today.year), parseInt(this.today.month), 0).getDate()
    this.today.week = new Date(parseInt(this.today.year), parseInt(this.today.month) - 1, 1).getDay()
    const {curMonth, prevMonth, nextMonth} = this.initDate(parseInt(this.today.year), parseInt(this.today.month))
    let calendarData = Taro.getStorageSync('calendarData')
    const md = this.today.month + '-' + this.today.day
    if (!calendarData) {
      calendarData = await this.getCalendarData()
    } else {
      if (md === '01-01') {
        calendarData = await this.getCalendarData()
      }
    }
    const calendar = this.makeCalendar(curMonth, prevMonth, nextMonth)
    calendar.map((item) => {
      calendarData.map((items) => {
        if (item.value === items.date) {
          item.name = items.name
          item.status = items.status
        }
      })
    })
    const {isSeller} = await user.getUserData()
    const {start, end} = this.props.selectDate
    if (start && end && this.props.type === 'range') {
      this.setState({calendar, curMonth, prevMonth, nextMonth, isSeller, isGroup})
    } else {
      this.setState({calendar, curMonth, prevMonth, nextMonth, isSeller, isGroup})
    }
  }

  async monthChange(type) {
    if (type === 'prev') {
      if (new Date(parseInt(this.state.curMonth.year), parseInt(this.state.curMonth.month) - 1, 1).getTime() > this.today.timestamp) {
        const {curMonth, prevMonth, nextMonth} = this.initDate(parseInt(this.state.prevMonth.year), parseInt(this.state.prevMonth.month))
        let calendarData = Taro.getStorageSync('calendarData')
        const md = curMonth.month + '-' + curMonth.day
        if (!calendarData) {
          calendarData = await this.getCalendarData()
        } else {
          if (md === '01-01') {
            calendarData = await this.getCalendarData()
          }
        }
        const calendar = this.makeCalendar(curMonth, prevMonth, nextMonth)
        calendar.map((item) => {
          calendarData.map((items) => {
            if (item.value === items.date) {
              item.name = items.name
              item.status = items.status
            }
          })
        })
        this.setState({calendar, curMonth, prevMonth, nextMonth})
      } else {
        Taro.showToast({
          title: '前面没有了~',
          icon: 'none'
        })
      }
    } else {
      const {curMonth, prevMonth, nextMonth} = this.initDate(parseInt(this.state.nextMonth.year), parseInt(this.state.nextMonth.month))
      let calendarData = Taro.getStorageSync('calendarData')
      const md = curMonth.month + '-' + curMonth.day
      if (!calendarData) {
        calendarData = await this.getCalendarData()
      } else {
        if (md === '01-01') {
          calendarData = await this.getCalendarData()
        }
      }
      const calendar = this.makeCalendar(curMonth, prevMonth, nextMonth)
      calendar.map((item) => {
        calendarData.map((items) => {
          if (item.value === items.date) {
            item.name = items.name
            item.status = items.status
          }
        })
      })
      this.setState({calendar, curMonth, prevMonth, nextMonth})
    }
  }

  // month为实际显示月份
  initDate(year: number, month: number): { curMonth: CurMonth; prevMonth: PrevMonth; nextMonth: NextMonth } {
    const curMonth = {year: '', month: '', count: 0, week: 0, day: ''}
    const prevMonth = {count: 0, month: '', year: ''}
    const nextMonth = {month: '', year: ''}
    const now = new Date(year, month - 1, 1)
    curMonth.month = now.getMonth() + 1 < 10 ? '0' + (now.getMonth() + 1) : `${now.getMonth() + 1}`
    curMonth.day = now.getDate() < 10 ? '0' + now.getDate() : `${now.getDate()}`
    curMonth.year = now.getFullYear() < 10 ? '0' + now.getFullYear() : `${now.getFullYear()}`
    curMonth.count = new Date(parseInt(curMonth.year), parseInt(curMonth.month), 0).getDate()
    curMonth.week = new Date(parseInt(curMonth.year), parseInt(curMonth.month) - 1, 1).getDay()
    if (parseInt(curMonth.month) - 1 <= 0) {
      prevMonth.month = '12'
      prevMonth.year = `${parseInt(curMonth.year) - 1}`
    } else {
      prevMonth.month = parseInt(curMonth.month) - 1 < 10 ? `0${parseInt(curMonth.month) - 1}` : `${parseInt(curMonth.month) - 1}`
      prevMonth.year = curMonth.year
    }
    if (parseInt(curMonth.month) + 1 > 12) {
      nextMonth.month = '01'
      nextMonth.year = `${parseInt(curMonth.year) + 1}`
    } else {
      nextMonth.month = parseInt(curMonth.month) + 1 < 10 ? `0${parseInt(curMonth.month) + 1}` : `${parseInt(curMonth.month) + 1}`
      nextMonth.year = curMonth.year
    }
    prevMonth.count = new Date(parseInt(prevMonth.year), parseInt(prevMonth.month), 0).getDate()
    return {curMonth, prevMonth, nextMonth}
  }

  makeCalendar(curMonth: CurMonth, prevMonth: PrevMonth, nextMonth: NextMonth) {
    const prevMonthArr = Array.from(new Array(prevMonth.count).keys())
    const calendar: CalendarData[] = []
    const slicePrevMonthDay = prevMonthArr.slice(curMonth.week * -1)
    for (let i = 0; i < 7 * 6; i++) {
      if (i < curMonth.week) {

        calendar.push({
          day: slicePrevMonthDay[i] + 1 < 10 ? `0${slicePrevMonthDay[i] + 1}` : `${slicePrevMonthDay[i] + 1}`,
          valid: new Date(parseInt(prevMonth.year), parseInt(prevMonth.month) - 1, slicePrevMonthDay[i] + 1).getTime() >= this.today.timestamp,
          value: `${prevMonth.year}-${prevMonth.month}-${slicePrevMonthDay[i] + 1}`,
          isWeekend: i % 7 === 0 || i % 7 === 6,
          prev: true,
          next: false,
        } as CalendarData)
      } else if (i >= curMonth.week && i < curMonth.week + curMonth.count) {
        const todayNum = i - curMonth.week + 1
        const thisdate = `${curMonth.year}-${curMonth.month}-${todayNum < 10 ? `0${todayNum}` : `${todayNum}`}`
        let valid = new Date(thisdate).getTime() >= this.today.timestamp
        if (this.props.type === 'range' && this.props.time_end) {
          if (this.today.text == thisdate) {
            const now = new Date().getTime()
            if (now > this.today.selftimestamp) {
              valid = false
            }
          }
        }
        calendar.push({
          day: todayNum < 10 ? `0${todayNum}` : `${todayNum}`,
          valid,
          value: `${curMonth.year}-${curMonth.month}-${todayNum < 10 ? `0${todayNum}` : `${todayNum}`}`,
          isWeekend: i % 7 === 0 || i % 7 === 6,
          prev: false,
          next: false,
        } as CalendarData)
      } else {
        const todayNum = i - curMonth.week - curMonth.count + 1
        calendar.push({
          day: todayNum < 10 ? `0${todayNum}` : `${todayNum}`,
          valid: new Date(`${nextMonth.year}-${nextMonth.month}-${todayNum < 10 ? `0${todayNum}` : `${todayNum}`}`).getTime() >= this.today.timestamp,
          value: `${nextMonth.year}-${nextMonth.month}-${todayNum < 10 ? `0${todayNum}` : `${todayNum}`}`,
          isWeekend: i % 7 === 0 || i % 7 === 6,
          prev: false,
          next: true,
        } as CalendarData)
      }
    }
    return this.bindServerDateData(calendar, this.props.data || [])
  }

  timeCompare(time1, time2) {
    const startValue = new Date(time1)
    const endValue = new Date(time2)
    return (Date.parse(startValue) + 86400000) >= Date.parse(endValue)
  }

  bindServerDateData(calendar: CalendarData[], serverDateData: ServerDateData[]) {
    const convertData: { [key: string]: ServerDateData } = {}
    serverDateData.map(item => {
      convertData[item.date] = item
    })
    calendar.forEach(item => {
      item.data = convertData[item.value] || ''
    });
    return calendar
  }

  dateClick(item, e) {
    e.stopPropagation()
    if (item.valid) {
      if (this.props.type === 'single') {
        if (item.data) {
          if (item.data.stock_balance != 0) {
            this.setState({single: item.value, confirmBtn: true}, async () => {
              this.confirm()
            })
          } else {
            Taro.showToast({title: this.props.category == 1 ? "该天已售罄" : "该天已约满", icon: 'none'})
          }
        }
      } else if (this.props.type === 'range') {
        const {start, end} = this.state
        const {goodsType, continuousType, lateNum} = this.props
        if (goodsType === 2) {
          if (continuousType !== 2) {
            this.setState({start: item.value, confirmBtn: true}, async () => {
              let text = ''
              const val = new Date(item.value).getTime() + (60 * 60 * 24 * 1000) * lateNum
              const date = new Date(val)
              text += date.getFullYear() + '-'
              text += date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
              text += '-'
              text += date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
              const range = this.calcRange(this.state.start, text)
              const info = await http.carGet(CHECK_DAY_INFO, {
                goodsUuid: this.props.goodsId,
                uuid: this.props.goodId,
                appointmentDateRange: JSON.stringify({start: item.value, end: text, range})
              })
              this.confirm()
              if (!info) {
                this.setState({end: text, range, confirmBtn: true}, async () => {
                  this.confirm()
                })
              }
            })
          }
          if (continuousType === 2) {
            if ((start && end) || (start && new Date(start).getTime() > new Date(item.value).getTime())) {
              this.setState({start: item.value, end: '', range: '', confirmBtn: goodsType !== 2}, async () => {
                this.confirm()
              })
            } else if (!start) {
              this.setState({start: item.value, confirmBtn: true}, async () => {
                this.confirm()
              })
            } else if (start && new Date(start).getTime() < new Date(item.value).getTime()) {
              const range = this.calcRange(start, item.value)
              this.setState({end: item.value, range, confirmBtn: true}, async () => {
                this.confirm()
              })
            }
          }
        } else {
          if (start && end) {
            this.setState({start: item.value, end: '', range: '', confirmBtn: goodsType !== 2}, async () => {
              this.confirm()
            })
          } else if (!start) {
            this.setState({start: item.value})
          } else if (new Date(start).getTime() >= new Date(item.value).getTime()) {
            this.setState({start: item.value})
          } else if (end) {
            this.setState({start: '', end: ''})
          } else {
            if (this.props.continuousType === 2) {
              const range = this.calcRange(start, item.value)
              this.setState({end: item.value, range, confirmBtn: true}, async () => {
                this.confirm()
              })
            } else {
              if (!end) {
                if (this.timeCompare(this.state.start, item.value)) {
                  this.setState({end: item.value, confirmBtn: true}, async () => {
                    this.confirm()
                  })
                } else {
                  this.setState({start: item.value, confirmBtn: false})
                }
              }
            }
          }
        }
      }
    }
  }

  calcRange(start, end) {
    const startTime = new Date(start).getTime()
    const endTime = new Date(end).getTime()
    const range: string[] = []
    let i = 1
    while (true) {
      const newTime = startTime + (i * 24 * 60 * 60 * 1000)
      if (newTime >= endTime) break;
      const newTimeDate = new Date(newTime)
      let text = ''
      text += newTimeDate.getFullYear() + '-'
      text += newTimeDate.getMonth() + 1 < 10 ? '0' + (newTimeDate.getMonth() + 1) : newTimeDate.getMonth() + 1
      text += '-'
      text += newTimeDate.getDate() < 10 ? '0' + newTimeDate.getDate() : newTimeDate.getDate()
      range.push(text)
      i++
    }
    return range
  }

  calcTomorrow(start) {
    const startTime = new Date(start).getTime()
    const newTime = startTime + (24 * 60 * 60 * 1000)
    const newTimeDate = new Date(newTime)
    let text = ''
    text += newTimeDate.getFullYear() + '-'
    text += newTimeDate.getMonth() + 1 < 10 ? '0' + (newTimeDate.getMonth() + 1) : newTimeDate.getMonth() + 1
    text += '-'
    text += newTimeDate.getDate() < 10 ? '0' + newTimeDate.getDate() : newTimeDate.getDate()
    return text
  }

  getStockBalance(item) {
    if (!item.stock_balance) {
      return true
    }
    return Number(item.stock_balance) <= 0;
  }

  confirm() {
    const {start, end, range, single} = this.state
    const data = {start, end, type: this.props.type, single, range}
    if (this.props.mode === 'callback') {
      if (typeof this.props.onConfirm === 'function') {
        this.props.onConfirm(data)
      }
    } else {
      if (this.props.type === 'single') {
        this.props.selectDateAction({start: this.state.single, end: this.calcTomorrow(this.state.single), list: []})
      } else {
        this.props.selectDateAction({start, end, list: range})
      }
      if (typeof this.props.onConfirm === 'function') {
        this.props.onConfirm(data)
      }
    }
  }

  fixDisplay(val) {
    val = val.toString()
    if (val.startsWith('0')) {
      val = val.replace('0', '')
    }
    return val
  }

  render() {
    const {calendar, isGroup, curMonth, nextMonth, start, end, single, range, prevMonth, isSeller} = this.state
    return (
      <View className='calendarRoot appointmentCalendar'>
        <View className='main'>
          <View className='head'>
            <View className='btn prevMonth' onClick={this.monthChange.bind(this, 'prev')}>上一月</View>
            <View className='title'>{curMonth.year}年{curMonth.month}月</View>
            <View className='btn nextMonth' onClick={this.monthChange.bind(this, 'next')}>下一月</View>
          </View>
          <View className='week'>
            {this.week.map((item, index) => <View key={index} className='week-item'>{item}</View>)}
          </View>
          <ScrollView
            scrollY
            className='scrollview'
            scrollWithAnimation
            scrollAnchoring
          >
            <View className='day-box'>
              {calendar.map((item, index) => <View onClick={this.dateClick.bind(this, item)} key={index}
                                                   className={`day-item ${item.isWeekend && 'weekend'} ${(this.getStockBalance(item.data)) && 'invalid'} ${single === item.value && 'single'} ${start === item.value && this.props.goodsType === 2 && 'start'} ${end === item.value && this.props.goodsType === 2 && 'end'} ${range.includes(item.value) && 'range'} ${(start === item.value && this.props.goodsType === 1) && 'start-s'} ${(end === item.value && this.props.goodsType === 1) && 'end-e'}`}
              >
                <View className='calendar-header'>
                  {!!item.name && <View className='holidays'>{item.name || ''}</View>}
                  {item.status && !item.name && <View
                    className={`rest-work ${item.status === 1 ? '' : 'work-days'}`}
                  >{item.status === 1 ? '休' : '班'}</View>}
                </View>
                <View className='day'><Text
                  style='font-size:8px; color: #aaa;'
                >{item.next ? `${this.fixDisplay(nextMonth.month)}月` : ''}{item.prev ? `${this.fixDisplay(prevMonth.month)}月` : ''}</Text>{this.fixDisplay(item.day)}日</View>
                {item.data && <Block>
                  {!!item.data.price && !isGroup &&
                  <View className='text market-price'><Text className='info-text' decode>补差:¥</Text>{item.data.price}
                  </View>}
                  {!!item.data.seller_price && isSeller && !isGroup &&
                  <View className='text price'><Text className='info-text'
                                                     decode
                  >分:¥&nbsp;</Text>{item.data.seller_price}</View>}
                  {!!item.data.stock_balance && !isGroup && <View className='text price'><Text className='info-text'
                                                                                               decode
                  >余:&nbsp;</Text>{item.data.stock_balance}
                  </View>}
                  {isGroup &&
                  <View className='text price'><Text className='info-text' decode>¥:&nbsp;</Text>{item.data.price}
                  </View>}
                  {!!item.data.stock_balance && (item.data.stock_balance > 0 && item.data.stock_balance <= 10) &&
                  <View className='text price error'><Text
                    className='info-text'
                  >{this.props.goodsType === 2 ? '房源紧张' : '票务紧张'}</Text></View>}
                  {!item.data.stock_balance && <View className='text price error'><Text className='info-text'
                                                                                        decode
                  >{this.props.category == 1 ? "售罄" : "已约满"}</Text></View>}
                </Block>}
              </View>)}
            </View>
          </ScrollView>
        </View>
      </View>
    )
  }
}

export default Calendar as ComponentClass<PageOwnProps, PageState>
